package poker;

import java.util.*;
import java.awt.image.BufferedImage;
import javax.imageio.*;
import java.io.*;
import javax.swing.ImageIcon;

/**
 * Class that can calculate a numerical value for a hand of playing cards.
 * @author Matt
 */
public class HandEvaluator {

    /**
     * Public constructor for the HandEvaluator.
     */
    HandEvaluator()
    {
    }

    /**
     * Returns the value of the current hand.
     * @return the value of the current hand.
     */
    public long getHandValue(ArrayList<Card> fullHand)
    {
        this.fullHand = fullHand;
        fullHandSortedByPairs = pairSort(fullHand);
        fullHandSortedByValue = valueSort(fullHand);
        fullHandSortedByValueNoSame = valueNoSameSort(fullHand);
        majorSuit = findMajorSuit();

        long value;
        String hValue = "1";

        value = getRoyalFlush();
        if(value != -1)
            return value;

        value = getStraightFlush();
        if(value != -1)
            return value;

        value = get4Kind();
        if(value != -1)
            return value;

        value = getFullHouse();
        if(value != -1)
            return value;

        value = getFlush();
        if(value != -1)
            return value;

        value = getStraight();
        if(value != -1)
            return value;

        value = get3Kind();
        if(value != -1)
            return value;

        value = get2Pair();
        if(value != -1)
            return value;

        value = getPair();
        if(value != -1)
            return value;

        for(int i = 0; i < 5; i++)
        {
            hValue += numberFormat(fullHandSortedByValue.get(i).getValue());
        }

        return Long.parseLong(hValue);
    }

    //works
    private long getRoyalFlush()
    {
        ArrayList<Card> best5Hand = new ArrayList<Card>();
        long handValue;
        if(majorSuit.equals(""))
            return -1;

        for(int i = 14; i > 9; i--)
        {
            for(int k = 0; k < 7; k++)
            {
                if (fullHand.get(k).getValue() == i &&
                        fullHand.get(k).getSuit().equals(majorSuit))
                {
                    best5Hand.add(fullHand.get(k));
                    break;
                }
            }
        }

        if(best5Hand.size() == 5)
            return 101413121110L;
        else return -1;
    }

    //works
    private long getStraightFlush()
    {
        ArrayList<Card> flushHand = new ArrayList<Card>();
        boolean isStraight = false;

        String hValue = "9";

        if(majorSuit.equals("") || fullHandSortedByValueNoSame.size() < 5)
            return -1;
        else
        {
            for(int i = 0; i < 7; i++)
            {
                if(fullHandSortedByValue.get(i).getSuit().equals(majorSuit))
                {
                    flushHand.add(fullHandSortedByValue.get(i));
                }
            }

            if(flushHand.get(0).getValue() == 14)
            {
                 ImageIcon icon = null;
                 icon = new ImageIcon("src/classic-cards/b2pt.png");

                 flushHand.add(new Card(
                        1, "AceLow", icon, true));
            }

            for(int i = 0; i < (flushHand.size() - 4); i++)
            {
                if((flushHand.get(0 + i).getValue() -
                        flushHand.get(4 + i).getValue()) == 4)
                {
                    isStraight = true;
                    for(int k = 0; k < 5; k++)
                    {
                        if(flushHand.get(k + i).getValue() == 1)
                        {
                            hValue += "14";
                        }
                        else
                        {
                            hValue += numberFormat(flushHand.get(k + i).getValue());
                        }
                    }
                    break;
                }
            }

            if(isStraight)
                return Long.parseLong(hValue);
            else return -1;
        }
    }

    //works
    private long get4Kind()
    {
        String hValue = "8";
        int pairValue;
        if(fullHandSortedByPairs.size() > 3)
        {
            if(fullHandSortedByPairs.get(0).getValue() ==
                    fullHandSortedByPairs.get(1).getValue() &&
                    fullHandSortedByPairs.get(0).getValue() ==
                    fullHandSortedByPairs.get(2).getValue() &&
                    fullHandSortedByPairs.get(0).getValue() ==
                    fullHandSortedByPairs.get(3).getValue())

              {
            pairValue = fullHandSortedByPairs.get(0).getValue();
            hValue += numberFormat(pairValue) + numberFormat(pairValue) +
                    numberFormat(pairValue) + numberFormat(pairValue);

            for(int i = 0; i < 7; i++)
            {
                if(fullHandSortedByValue.get(i).getValue() != pairValue)
                {
                     hValue += numberFormat(
                             fullHandSortedByValue.get(i).getValue());
                     break;
                }
            }

            return Long.parseLong(hValue);
        } else return -1;
        } else return -1;

    }

    //works
    private long getFullHouse()
    {
        String hValue = "7";
        int pair1Value;
        int pair2Value;
        if(fullHandSortedByPairs.size() > 4)
        {
        if(fullHandSortedByPairs.get(0).getValue() ==
                fullHandSortedByPairs.get(1).getValue() &&
                fullHandSortedByPairs.get(0).getValue() ==
                fullHandSortedByPairs.get(2).getValue() &&
                fullHandSortedByPairs.get(3).getValue() ==
                fullHandSortedByPairs.get(4).getValue())
        {
            pair1Value = fullHandSortedByPairs.get(0).getValue();
            pair2Value = fullHandSortedByPairs.get(3).getValue();

            hValue += numberFormat(pair1Value) + numberFormat(pair1Value) +
                    numberFormat(pair1Value) + numberFormat(pair2Value) +
                    numberFormat(pair2Value);

            return Long.parseLong(hValue);
        }
        else return -1;
        } else return -1;
    }

    //works
    private long getFlush()
    {
        ArrayList<Card> best5Hand = new ArrayList<Card>();
        int count = 0;
        String hValue = "6";

        if(majorSuit.equals(""))
            return -1;
        else
        {
            for(int i = 0; i < 7; i++)
            {
                if(fullHandSortedByValue.get(i).getSuit().equals(majorSuit))
                {
                    best5Hand.add(fullHandSortedByValue.get(i));
                    count++;
                }

                if(count == 5)
                    break;
            }

            for(int k = 0; k < 5; k++)
            {
                hValue += numberFormat(
                             best5Hand.get(k).getValue());
            }

            return Long.parseLong(hValue);
        }
    }

    //works
    private long getStraight()
    {
        String hValue = "5";
        boolean isStraight = false;
        ArrayList<Card> straightHand =
                new ArrayList<Card>(fullHandSortedByValueNoSame.size());
        straightHand.addAll(fullHandSortedByValueNoSame);

        if(straightHand.size() < 5)
            return -1;

        if(straightHand.get(0).getValue() == 14)
        {
             ImageIcon icon = null;
             icon = new ImageIcon("src/classic-cards/b2pt.png");
             straightHand.add(new Card(
                     1, "AceLow", icon, true));
        }

        for(int i = 0; i < (straightHand.size() - 4); i++)
        {
            if((straightHand.get(0 + i).getValue() -
                    straightHand.get(4 + i).getValue()) == 4)
            {
                isStraight = true;
                for(int k = 0; k < 5; k++)
                {
                    if(straightHand.get(k + i).getValue() == 1)
                    {
                        hValue += "14";
                    }
                    else
                    {
                    hValue += numberFormat(straightHand.get(k + i).getValue());
                    }
                }
                break;
            }
        }

        if(isStraight)
            return Long.parseLong(hValue);
        else return -1;
    }

    //works
    private long get3Kind()
    {
        String hValue = "4";
        int count = 0;
        int index = 0;
        int pairValue;

        if(fullHandSortedByPairs.size() > 2)
        {
        if(fullHandSortedByPairs.get(0).getValue() ==
                fullHandSortedByPairs.get(1).getValue() &&
                fullHandSortedByPairs.get(0).getValue() ==
                fullHandSortedByPairs.get(2).getValue())
        {
            pairValue = fullHandSortedByPairs.get(0).getValue();
            hValue += numberFormat(pairValue) + numberFormat(pairValue) +
                    numberFormat(pairValue);

            while(count < 2)
            {
                if(fullHandSortedByValue.get(index).getValue() != pairValue)
                {
                    hValue += numberFormat(
                            fullHandSortedByValue.get(index).getValue());
                    count++;
                }
                index++;
            }

            return Long.parseLong(hValue);
        }
        else return -1;
        } else return -1;
    }

    //works
    private long get2Pair()
    {
        String hValue = "3";
        int pair1Value;
        int pair2Value;
        int pairValueSwap;

        if(fullHandSortedByPairs.size() > 3)
        {

        if(fullHandSortedByPairs.get(0).getValue() ==
                fullHandSortedByPairs.get(1).getValue() &&
                fullHandSortedByPairs.get(2).getValue() ==
                fullHandSortedByPairs.get(3).getValue())
        {

            pair1Value = fullHandSortedByPairs.get(0).getValue();
            pair2Value = fullHandSortedByPairs.get(2).getValue();

            if(pair1Value < pair2Value)
            {
                pairValueSwap = pair2Value;
                pair2Value = pair1Value;
                pair1Value = pairValueSwap;
            }

            hValue += numberFormat(pair1Value) + numberFormat(pair1Value) +
                    numberFormat(pair2Value) + numberFormat(pair2Value);

            for(int i = 0; i < 7; i++)
            {
                if((fullHandSortedByValue.get(i).getValue() != pair1Value) &&
                        (fullHandSortedByValue.get(i).getValue() != pair2Value))
                {
                     hValue += numberFormat(
                             fullHandSortedByValue.get(i).getValue());
                     break;
                }
            }

            return Long.parseLong(hValue);
        }
        else return -1;
        } else return -1;
    }

    //works
    private long getPair()
    {
        String hValue = "2";
        int count = 0;
        int index = 0;
        int pairValue;

        if(fullHandSortedByPairs.size() > 1)
        {
        if(fullHandSortedByPairs.get(0).getValue() ==
                fullHandSortedByPairs.get(1).getValue())
        {
            pairValue = fullHandSortedByPairs.get(0).getValue();
            hValue += numberFormat(pairValue) + numberFormat(pairValue);

            while(count < 3)
            {
                if(fullHandSortedByValue.get(index).getValue() != pairValue)
                {
                    hValue += numberFormat(
                            fullHandSortedByValue.get(index).getValue());
                    count++;
                }
                index++;
            }

            return Long.parseLong(hValue);
        }
        else return -1;
        } else return -1;
    }

    //Returns the name of the suit if there are 5 or more
    //of it and returns null if there is not.
    private String findMajorSuit()
    {
        int count = 0;
        String[] suits = {"Club", "Spade", "Heart", "Diamond"};
        for(String s : suits)
        {
            for(int i = 0; i < 7; i++)
            {
                if(fullHand.get(i).getSuit().equals(s))
                    count++;
            }

            if(count > 4)
                return s;
            else count = 0;
        }
        return "";
    }

    //Sorts from high to low
    private ArrayList<Card> valueSort(ArrayList<Card> hand)
    {
        ArrayList<Card> handCopy = new ArrayList(hand.size());
        handCopy.addAll(hand);
        int highValue = 0;
        int highCardIndex = -1;
        boolean duplicate = false;
        ArrayList<Card> sorted = new ArrayList<Card>();
        while(!handCopy.isEmpty())
        {
            for(int i = 0; i < handCopy.size(); i++)
            {
                if(handCopy.get(i).getValue() > highValue)
                {
                    highValue = handCopy.get(i).getValue();
                    highCardIndex = i;
                }
            }

            sorted.add(handCopy.remove(highCardIndex));
            
            highValue = 0;
            highCardIndex = -1;
        }
        return sorted;
    }

    //Sorts from high to low removing multiples
    private ArrayList<Card> valueNoSameSort(ArrayList<Card> hand)
    {
        ArrayList<Card> handCopy = new ArrayList(hand.size());
        handCopy.addAll(hand);
        int highValue = 0;
        int highCardIndex = -1;
        boolean duplicate = false;
        ArrayList<Card> sorted = new ArrayList<Card>();
        while(!handCopy.isEmpty())
        {
            for(int i = 0; i < handCopy.size(); i++)
            {
                if(handCopy.get(i).getValue() > highValue)
                {
                    highValue = handCopy.get(i).getValue();
                    highCardIndex = i;
                }
            }

            if(sorted.isEmpty())
            {
                sorted.add(handCopy.remove(highCardIndex));
            }
            else
            {
                for(int k = 0; k < sorted.size(); k++)
                {
                    if(handCopy.get(highCardIndex).getValue() == sorted.get(k).getValue())
                        duplicate = true;
                }

                if(duplicate)
                {
                    Card c = handCopy.remove(highCardIndex);
                }
                else
                {
                    sorted.add(handCopy.remove(highCardIndex));
                }
            }
            highValue = 0;
            highCardIndex = -1;
        }
        return sorted;
    }

    //Sorts from greatest pairs to greatest value to high card to low card
    //ex. three of kind first then a pair then the last two cards from high to low
    //ex. higher pair then other pair then the last three cards from high to low
    private ArrayList<Card> pairSort(ArrayList<Card> hand)
    {
        ArrayList<Card> handCopy = new ArrayList(hand.size());
        handCopy.addAll(hand);
        ArrayList<Card> hvs = valueSort(handCopy);//handValueSort
        ArrayList<Integer> pc = new ArrayList();//pairCards
        ArrayList<Card> hps = new ArrayList(hand.size());//handPairSort

        for (int i = 0; i < hvs.size(); i++)
        {
            if(hvs.size() - i > 1)
            {
                if(hvs.get(i).getValue() == hvs.get(i+1).getValue())
                {
                    if(hvs.size() - i > 2)
                    {
                        if(hvs.get(i).getValue() == hvs.get(i+2).getValue())
                        {
                            if(hvs.size() - i > 3)
                            {
                                if(hvs.get(i).getValue() == hvs.get(i+3).getValue())
                                {
                                    pc.add(i);
                                    pc.add(i+1);
                                    pc.add(i+2);
                                    pc.add(i+3);
                                }
                                else
                                {
                                    pc.add(i);
                                    pc.add(i+1);
                                    pc.add(i+2);
                                }
                            }
                            else
                            {
                                pc.add(i);
                                pc.add(i+1);
                                pc.add(i+2);
                            }
                        }
                        else
                        {
                            pc.add(i);
                            pc.add(i+1);
                        }
                    }
                    else
                    {
                        pc.add(i);
                        pc.add(i+1);
                    }
                }
            }
        }//end for

       // Card c;
       // boolean bool = false;

        for(int k = 0; k < pc.size(); k++)
        {
            for(int j = 0; j < pc.size(); j++)
            {
                if (k != j && pc.get(k) == pc.get(j))
                {
                    pc.set(j, -1);
                }
            }
        }

        for(int x = 0; x < pc.size(); x++)
        {
            if(pc.get(x) != -1)
                hps.add(hvs.get(pc.get(x)));
        }

//        for(int j = 0; j < hps.size(); j++)
//        {
//            c = hps.get(j);
//            for(int q = 0; q < hps.size(); q++)
//            {
//                if(c.getValue() == hps.get(q).getValue() &&
//                        c.getSuit().equals(hps.get(q).getSuit()) && q != j)
//                {
//                    bool = true;
//                }
//            }
//
//            if(!bool)
//            {
//                hps.add(c);
//            }
//            else
//            {
//                bool = false;
//            }
//        }

        return hps;
    }

    //Makes all numbers double digit. ex. 4 -> 04, 11 -> 11
    private String numberFormat(int x)
    {
        if(x > 9)
        {
            return Integer.toString(x);
        }
        else
        {
            return "0" + Integer.toString(x);
        }
    }

    public static void main(String[] args)
    {
        int faceCard = 0;
        int pair = 0;
        int twoPair = 0;
        int toak = 0;
        int flush = 0;
        int straight = 0;
        int fullHouse = 0;
        int foak = 0;
        int straightFlush = 0;
        int royalFlush = 0;

        String lonString = "";

        int n = 100;
        HandEvaluator he = new HandEvaluator();
        for(int i = 0; i < n; i++)
        {
            long lon;
            Deck d = new Deck();
            ArrayList<Card> list = new ArrayList();
            list.add(d.drawCard());
            list.add(d.drawCard());
            list.add(d.drawCard());
            list.add(d.drawCard());
            list.add(d.drawCard());

            Card c1 = d.drawCard();
            Card c2 = d.drawCard();

            ArrayList<Card> fullHand = new ArrayList(list.size());
            fullHand.addAll(list);
            fullHand.add(c1);
            fullHand.add(c2);

             Hand h = new Hand(c1, c2, list);

             lon = he.getHandValue(fullHand);

             lonString = Long.toString(lon);
             if (lonString.charAt(0) == '1' && lonString.charAt(1) == '0')
                 royalFlush++;
             else if (lonString.charAt(0) == '9')
                 straightFlush++;
             else if (lonString.charAt(0) == '8')
                 foak++;
             else if (lonString.charAt(0) == '7')
                 fullHouse++;
             else if (lonString.charAt(0) == '6')
                 flush++;
             else if (lonString.charAt(0) == '5')
                 straight++;
             else if (lonString.charAt(0) == '4')
                 toak++;
             else if (lonString.charAt(0) == '3')
                 twoPair++;
             else if (lonString.charAt(0) == '2')
                 pair++;
             else
                 faceCard++;
        }

        System.out.println("");
        System.out.println("Number of Trials - " + n);
        System.out.println("Face Cards - " + ((double)faceCard / n)*100 + "%");
        System.out.println("Pair - " + ((double)pair / n)*100 + "%");
        System.out.println("Two Pair - " + ((double)twoPair / n)*100 + "%");
        System.out.println("Three of a Kind - " + ((double)toak / n)*100 + "%");
        System.out.println("Straight - " + ((double)straight / n)*100 + "%");
        System.out.println("Flush - " + ((double)flush / n)*100 + "%");
        System.out.println("Full House - " + ((double)fullHouse / n)*100 + "%");
        System.out.println("Four of a Kind - " + ((double)foak / n)*100 + "%");
        System.out.println("Straight Flush - " + ((double)straightFlush / n)*100 + "%");
        System.out.println("Royal Flush - " + ((double)royalFlush / n)*100 + "%");
    }
    
    private String majorSuit;
    private ArrayList<Card> fullHand;
    private ArrayList<Card> fullHandSortedByPairs;
    private ArrayList<Card> fullHandSortedByValue;
    private ArrayList<Card> fullHandSortedByValueNoSame;
}